/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "core/include/hpm6e00_plic.h"
#include "riscv/riscv_core.h"
#include "core/include/hpm_interrupt.h"
#include "common/hpm_common.h"
#include <stdint.h>
#include <string.h>

/*******************************************************************************
 * Extern
 ******************************************************************************/
extern uint32_t __data_start_load;
extern uint32_t __data_start;
extern uint32_t __data_end;
extern uint32_t __relocate_code_start_load;
extern uint32_t __relocate_code_start;
extern uint32_t __relocate_code_end;

extern uint32_t __bss_start__;
extern uint32_t __bss_end__;

/*******************************************************************************
 * Macro operate
 *******************************************************************************/
#define DATA_START_LOAD            ((uint32_t)&__data_start_load)
#define DATA_START                 ((uint32_t)&__data_start)
#define DATA_END                   ((uint32_t)&__data_end)

#define RELOCATE_CODE_START_LOAD   ((uint32_t)&__relocate_code_start_load)
#define RELOCATE_CODE_START        ((uint32_t)&__relocate_code_start)
#define RELOCATE_CODE_END          ((uint32_t)&__relocate_code_end)

#define BSS_START                  ((uint32_t)&__bss_start__)
#define BSS_END                    ((uint32_t)&__bss_end__)

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief 初始化段
 */
void c_base_runtime_init(void){
    uint32_t length;

    length = DATA_END - DATA_START;

    if (DATA_START != DATA_START_LOAD) {
        memcpy((void *)DATA_START, (void *)DATA_START_LOAD, length);
    }

    length = BSS_END - BSS_START;
    memset((void *)BSS_START, 0, length);

    length = (RELOCATE_CODE_END - RELOCATE_CODE_START);
    if (0 != length) {
        memcpy((void *)RELOCATE_CODE_START,
               (void *)RELOCATE_CODE_START_LOAD,
                length);
    }
}

/**
 * \brief 清除中断
 */
__attribute__((weak)) void irq_clean_up(void){
    /* 关闭中断 */
    disable_irq_from_intc();
    /* 设置中断阈值 */
    intc_m_set_threshold(0);

    /* 设置所有中断为已完成 */
    for (uint32_t irq = 0; irq < 128; irq++) {
        intc_m_complete_irq(irq);
    }
    /* 清除所有 PLIC 使能位 */
    for (uint32_t i = 0; i < 4; i++) {
        *(volatile uint32_t *)(HPM_PLIC_BASE + HPM_PLIC_ENABLE_OFFSET + (i << 2)) = 0;
    }
}

/**
 * \brief PLIC 特性使能
 */
static void __plic_feature_enable(void){
    uint32_t plic_feature = 0;

    /* 设置平台级中断控制器特性，使用向量表，支持中断抢占*/
    plic_feature = HPM_PLIC_FEATURE_VECTORED_MODE | HPM_PLIC_FEATURE_PREEMPTIVE_PRIORITY_IRQ;

    __plic_set_feature(HPM_PLIC_BASE, plic_feature);
}

/**
 * \brief 系统初始化
 */
void system_init(void){
    fencei();

    /* 使能 MCYCLE */
    uint32_t mcounteren = read_csr(CSR_MCOUNTEREN);
    write_csr(CSR_MCOUNTEREN, mcounteren | 1);

    disable_global_irq(CSR_MSTATUS_MIE_MASK);
    disable_irq_from_intc();

    __plic_feature_enable();
    enable_irq_from_intc();
    enable_global_irq(CSR_MSTATUS_MIE_MASK);
}

